package smartgrid.conf;

import java.io.File;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import smartgrid.Constants;

@XmlRootElement(name = Constants.TAG_SMARTGRID)
public class SmartGridConf {
	
	private static final Logger	logger	= LoggerFactory
																					.getLogger(SmartGridConf.class);
	
	// General configuration
	private GeneralConf					generalConf;
	
	// Prosumers configuration
	private List<ProsumerConf>	prosumersConf;
	
	// Broker configuration
	private BrokerConf					brokerConf;
	
	// Provider configuration
	private ProviderConf				providerConf;
	
	// Regulator configuration
	private RegulatorConf				regulatorConf;
	
	
	/**
	 * Process XML configuration file
	 * 
	 * @param xmlFilename
	 *          XML configuration file
	 * @param xsdFilename
	 *          XSD configuration filename
	 * @return Configuration information
	 */
	public static SmartGridConf getConf(String xmlFilename, String xsdFilename) {
		
		SmartGridConf conf = new SmartGridConf();
		
		File xmlFile = new File(xmlFilename);
		File xsdFile = new File(xsdFilename);
		
		if ((xmlFile.exists()) && (xsdFile.exists())) {
			
			if (isValid(xmlFilename, xsdFilename)) {
				
				try {
					JAXBContext jaxbContext = JAXBContext
							.newInstance(SmartGridConf.class);
					Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
					
					File XMLFile = new File(xmlFilename);
					
					if (XMLFile.exists()) {
						conf = (SmartGridConf) jaxbUnmarshaller.unmarshal(XMLFile);
					}
					
				} catch(JAXBException e) {
					logger.debug(e.toString());
				}
				
			}
		}
		
		return conf;
	}
	
	
	/**
	 * Check the validity of the XML file against an XSD file
	 * 
	 * @param xmlFilename
	 *          XML filename
	 * @param xsdFilename
	 *          XSD filename
	 * @return True if valid, False otherwise
	 */
	public static boolean isValid(String xmlFilename, String xsdFilename) {
		boolean valid = false;
		
		try {
			SchemaFactory factory = SchemaFactory
					.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
			Schema schema = factory.newSchema(new StreamSource(xsdFilename));
			
			Validator validator = schema.newValidator();
			validator.validate(new StreamSource(xmlFilename));
			
			valid = true;
			
		} catch(SAXException e) {
			logger.debug(e.toString());
		} catch(Exception e) {
			logger.debug(e.toString());
		}
		
		return valid;
	}
	
	
	public GeneralConf getGeneralConf() {
		return this.generalConf;
	}
	
	
	@XmlElement(name = Constants.TAG_GENERAL)
	public void setGeneralConf(GeneralConf generalConf) {
		this.generalConf = generalConf;
	}
	
	
	public List<ProsumerConf> getProsumersConf() {
		return this.prosumersConf;
	}
	
	
	@XmlElementWrapper(name = Constants.TAG_PROSUMERS)
	@XmlElement(name = Constants.TAG_PROSUMER)
	public void setProsumersConf(List<ProsumerConf> prosumersConf) {
		this.prosumersConf = prosumersConf;
	}
	
	
	public BrokerConf getBrokerConf() {
		return this.brokerConf;
	}
	
	
	@XmlElement(name = Constants.TAG_BROKER)
	public void setBrokerConf(BrokerConf brokerConf) {
		this.brokerConf = brokerConf;
	}
	
	
	public ProviderConf getProviderConf() {
		return this.providerConf;
	}
	
	
	@XmlElement(name = Constants.TAG_PROVIDER)
	public void setProviderConf(ProviderConf providerConf) {
		this.providerConf = providerConf;
	}
	
	
	public RegulatorConf getRegulatorConf() {
		return this.regulatorConf;
	}
	
	
	@XmlElement(name = Constants.TAG_REGULATOR)
	public void setRegulatorConf(RegulatorConf regulatorConf) {
		this.regulatorConf = regulatorConf;
	}
}